import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _typeof from "@babel/runtime/helpers/esm/typeof";
import { createVNode as _createVNode } from "vue";
import _regeneratorRuntime from "@babel/runtime/regenerator";

var __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function (resolve) {
      resolve(value);
    });
  }

  return new (P || (P = Promise))(function (resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }

    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }

    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }

    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};

var __rest = this && this.__rest || function (s, e) {
  var t = {};

  for (var p in s) {
    if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  }

  if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
    if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  }
  return t;
};

import defaultRequest from './request';
import getUid from './uid';
import attrAccept from './attr-accept';
import traverseFileTree from './traverseFileTree';
import { uploadProps } from './interface';
import { defineComponent, onBeforeUnmount, onMounted, ref } from 'vue';
import pickAttrs from '../_util/pickAttrs';
import partition from 'lodash-es/partition';
export default defineComponent({
  name: 'AjaxUploader',
  inheritAttrs: false,
  props: uploadProps(),
  setup: function setup(props, _ref) {
    var _this = this;

    var slots = _ref.slots,
        attrs = _ref.attrs,
        expose = _ref.expose;
    var uid = ref(getUid());
    var reqs = {};
    var fileInput = ref();
    var isMounted = false;
    /**
     * Process file before upload. When all the file is ready, we start upload.
     */

    var processFile = function processFile(file, fileList) {
      return __awaiter(_this, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
        var beforeUpload, transformedFile, action, mergedAction, data, mergedData, parsedData, parsedFile, mergedParsedFile;
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                beforeUpload = props.beforeUpload;
                transformedFile = file;

                if (!beforeUpload) {
                  _context.next = 14;
                  break;
                }

                _context.prev = 3;
                _context.next = 6;
                return beforeUpload(file, fileList);

              case 6:
                transformedFile = _context.sent;
                _context.next = 12;
                break;

              case 9:
                _context.prev = 9;
                _context.t0 = _context["catch"](3);
                // Rejection will also trade as false
                transformedFile = false;

              case 12:
                if (!(transformedFile === false)) {
                  _context.next = 14;
                  break;
                }

                return _context.abrupt("return", {
                  origin: file,
                  parsedFile: null,
                  action: null,
                  data: null
                });

              case 14:
                // Get latest action
                action = props.action;

                if (!(typeof action === 'function')) {
                  _context.next = 21;
                  break;
                }

                _context.next = 18;
                return action(file);

              case 18:
                mergedAction = _context.sent;
                _context.next = 22;
                break;

              case 21:
                mergedAction = action;

              case 22:
                // Get latest data
                data = props.data;

                if (!(typeof data === 'function')) {
                  _context.next = 29;
                  break;
                }

                _context.next = 26;
                return data(file);

              case 26:
                mergedData = _context.sent;
                _context.next = 30;
                break;

              case 29:
                mergedData = data;

              case 30:
                parsedData = // string type is from legacy `transformFile`.
                // Not sure if this will work since no related test case works with it
                (_typeof(transformedFile) === 'object' || typeof transformedFile === 'string') && transformedFile ? transformedFile : file;

                if (parsedData instanceof File) {
                  parsedFile = parsedData;
                } else {
                  parsedFile = new File([parsedData], file.name, {
                    type: file.type
                  });
                }

                mergedParsedFile = parsedFile;
                mergedParsedFile.uid = file.uid;
                return _context.abrupt("return", {
                  origin: file,
                  data: mergedData,
                  parsedFile: mergedParsedFile,
                  action: mergedAction
                });

              case 35:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, null, [[3, 9]]);
      }));
    };

    var post = function post(_ref2) {
      var data = _ref2.data,
          origin = _ref2.origin,
          action = _ref2.action,
          parsedFile = _ref2.parsedFile;

      if (!isMounted) {
        return;
      }

      var onStart = props.onStart,
          customRequest = props.customRequest,
          name = props.name,
          headers = props.headers,
          withCredentials = props.withCredentials,
          method = props.method;
      var uid = origin.uid;
      var request = customRequest || defaultRequest;
      var requestOption = {
        action: action,
        filename: name,
        data: data,
        file: parsedFile,
        headers: headers,
        withCredentials: withCredentials,
        method: method || 'post',
        onProgress: function onProgress(e) {
          var onProgress = props.onProgress;
          onProgress === null || onProgress === void 0 ? void 0 : onProgress(e, parsedFile);
        },
        onSuccess: function onSuccess(ret, xhr) {
          var onSuccess = props.onSuccess;
          onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(ret, parsedFile, xhr);
          delete reqs[uid];
        },
        onError: function onError(err, ret) {
          var onError = props.onError;
          onError === null || onError === void 0 ? void 0 : onError(err, ret, parsedFile);
          delete reqs[uid];
        }
      };
      onStart(origin);
      reqs[uid] = request(requestOption);
    };

    var reset = function reset() {
      uid.value = getUid();
    };

    var abort = function abort(file) {
      if (file) {
        var _uid = file.uid ? file.uid : file;

        if (reqs[_uid] && reqs[_uid].abort) {
          reqs[_uid].abort();
        }

        delete reqs[_uid];
      } else {
        Object.keys(reqs).forEach(function (uid) {
          if (reqs[uid] && reqs[uid].abort) {
            reqs[uid].abort();
          }

          delete reqs[uid];
        });
      }
    };

    onMounted(function () {
      isMounted = true;
    });
    onBeforeUnmount(function () {
      isMounted = false;
      abort();
    });

    var uploadFiles = function uploadFiles(files) {
      var originFiles = _toConsumableArray(files);

      var postFiles = originFiles.map(function (file) {
        // eslint-disable-next-line no-param-reassign
        file.uid = getUid();
        return processFile(file, originFiles);
      }); // Batch upload files

      Promise.all(postFiles).then(function (fileList) {
        var onBatchStart = props.onBatchStart;
        onBatchStart === null || onBatchStart === void 0 ? void 0 : onBatchStart(fileList.map(function (_ref3) {
          var origin = _ref3.origin,
              parsedFile = _ref3.parsedFile;
          return {
            file: origin,
            parsedFile: parsedFile
          };
        }));
        fileList.filter(function (file) {
          return file.parsedFile !== null;
        }).forEach(function (file) {
          post(file);
        });
      });
    };

    var onChange = function onChange(e) {
      var accept = props.accept,
          directory = props.directory;
      var files = e.target.files;

      var acceptedFiles = _toConsumableArray(files).filter(function (file) {
        return !directory || attrAccept(file, accept);
      });

      uploadFiles(acceptedFiles);
      reset();
    };

    var onClick = function onClick(e) {
      var el = fileInput.value;

      if (!el) {
        return;
      }

      var onClick = props.onClick; // TODO
      // if (children && (children as any).type === 'button') {
      //   const parent = el.parentNode as HTMLInputElement;
      //   parent.focus();
      //   parent.querySelector('button').blur();
      // }

      el.click();

      if (onClick) {
        onClick(e);
      }
    };

    var onKeyDown = function onKeyDown(e) {
      if (e.key === 'Enter') {
        onClick(e);
      }
    };

    var onFileDrop = function onFileDrop(e) {
      var multiple = props.multiple;
      e.preventDefault();

      if (e.type === 'dragover') {
        return;
      }

      if (props.directory) {
        traverseFileTree(Array.prototype.slice.call(e.dataTransfer.items), uploadFiles, function (_file) {
          return attrAccept(_file, props.accept);
        });
      } else {
        var files = partition(Array.prototype.slice.call(e.dataTransfer.files), function (file) {
          return attrAccept(file, props.accept);
        });
        var successFiles = files[0];
        var errorFiles = files[1];

        if (multiple === false) {
          successFiles = successFiles.slice(0, 1);
        }

        uploadFiles(successFiles);
        if (errorFiles.length && props.onReject) props.onReject(errorFiles);
      }
    };

    expose({
      abort: abort
    });
    return function () {
      var _cls;

      var _a;

      var Tag = props.componentTag,
          prefixCls = props.prefixCls,
          disabled = props.disabled,
          id = props.id,
          multiple = props.multiple,
          accept = props.accept,
          capture = props.capture,
          directory = props.directory,
          openFileDialogOnClick = props.openFileDialogOnClick,
          onMouseenter = props.onMouseenter,
          onMouseleave = props.onMouseleave,
          otherProps = __rest(props, ["componentTag", "prefixCls", "disabled", "id", "multiple", "accept", "capture", "directory", "openFileDialogOnClick", "onMouseenter", "onMouseleave"]);

      var cls = (_cls = {}, _defineProperty(_cls, prefixCls, true), _defineProperty(_cls, "".concat(prefixCls, "-disabled"), disabled), _defineProperty(_cls, attrs.class, !!attrs.class), _cls); // because input don't have directory/webkitdirectory type declaration

      var dirProps = directory ? {
        directory: 'directory',
        webkitdirectory: 'webkitdirectory'
      } : {};
      var events = disabled ? {} : {
        onClick: openFileDialogOnClick ? onClick : function () {},
        onKeydown: openFileDialogOnClick ? onKeyDown : function () {},
        onMouseenter: onMouseenter,
        onMouseleave: onMouseleave,
        onDrop: onFileDrop,
        onDragover: onFileDrop,
        tabindex: '0'
      };
      return _createVNode(Tag, _objectSpread(_objectSpread({}, events), {}, {
        "class": cls,
        "role": "button",
        "style": attrs.style
      }), {
        default: function _default() {
          return [_createVNode("input", _objectSpread(_objectSpread(_objectSpread({}, pickAttrs(otherProps, {
            aria: true,
            data: true
          })), {}, {
            "id": id,
            "type": "file",
            "ref": fileInput,
            "onClick": function onClick(e) {
              return e.stopPropagation();
            },
            "key": uid.value,
            "style": {
              display: 'none'
            },
            "accept": accept
          }, dirProps), {}, {
            "multiple": multiple,
            "onChange": onChange
          }, capture != null ? {
            capture: capture
          } : {}), null), (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)];
        }
      });
    };
  }
});